// 
//
// Author: Christopher Schwarzer
// Date: 02/2012
//
//

#include <string.h>
#include <sstream>
#include "ShapeSequence.h"
#include "ShapeOrganism.h"

using namespace std;

namespace Shape
{
    
ostream& operator<<(ostream& os, const Sequence& seq)
{
	os << "ID " << seq.ID() << " ps " << seq.SideToParent() << " size " << seq.Size() << " ";
	if (seq.Size() <= 4)
		return os;
		
	ConstSeqIter p = seq.Start() + 4;
	for (int i = 0; i < 4; i++)
	{
		if (*p & 0x80)
		{
			p++;
			os << 1 << " ";
		}
		else
		{
			int s = seq.GetWord(p);
			os << s << " ";
			p += s;
		}			
	}
	return os;
}

void Sequence::Serialize(const Organism& org)
{
	Clear();
	Serialize(*org.GetRoot());
}

Organism* Sequence::Deserialize() const
{
    std::string s;
    s.assign(bytes.begin(),bytes.end());
	Node* root = Deserialize(s);
	if (root == NULL)
		return NULL;

	Organism* org = new Organism();
	delete org->nodeList[0];
	org->nodeList.clear();
	root->parent = -1;
	// Now a post deserialization initialisation has to be done
	// to reconstruct various infos that was cut during serialization.
	// These are for the Shape: nodeList, nodeIDCount, map
	// and for each Node: pos, rot
	org->PostDeserializeInit(root, SIDE_NONE);
	
	return org;
}

void Sequence::Serialize(const Node& n) {
    stringstream rep;
    rep << "org:";
    Serialize(n,rep);
    std::string s = rep.str();
    bytes.assign(s.begin(),s.end());
}
    
void Sequence::Serialize(const Node& n, stringstream &rep)
{
   	rep << n.id << ":";
	rep << n.parent << ":";
    rep << n.rot;
	// check if we have any connections besides the one to the parent
	bool hasSubtrees = false;
	for (int i = 0; i < 4; i++)
	{
		if (i == n.parent)
			continue;
		if (n.connections[i] != NULL)
		{
			hasSubtrees = true;
			break;
		}
	}
	// Only write the subtree bytes if there is actually any one
    rep << "[";
    if (hasSubtrees)
	{
		for (int i = 0; i < 4; i++)
		{
			if (i == n.parent) {
//				Add(0xff);
                rep << -1 << "[]";
            } else if(n.connections[i] == NULL) {
//				Add(0x80);
                rep << -1 << "[]";
			} else {
				Serialize(*n.connections[i], rep);
            }
            
            if( i < 3){
                rep << ",";
            }
		}
    }
    rep << "]";
}
    
Node* Sequence::Deserialize(string s) const
{
	// if the first few bits are org:, this is not a subtree
	if (s.substr(0,4) == "org:")
	{
		return Deserialize(s.substr(4,string::npos));
	}
    
    stringstream buf(s);
	Node* n = new Node(0);
	buf >> n->id;
    
    if(n->id == -1){
        delete n;
        return NULL;
    }
    
    buf.get();
	buf >> n->parent;
	buf.get();
    buf >> n->rot;
    
    int cStart = (int)s.find("[");
    int cEnd = (int)s.rfind("]");
    
    string childs = s.substr(cStart+1,(cEnd-cStart)-1);
    vector<string> children = splitChildren(childs);
    
	if (children.size() > 1)
	{
        if(children.size() > 4){
            cerr << "Error - Shape::Sequence: Too many children for node" << endl;
        }
		for (int i = 0; i < 4; i++)
		{
			Node* c = Deserialize(children[i]);
			if (c != NULL)
			{
				n->connections[i] = c;
				c->connections[c->parent] = n;
			}
		}
	}
	return n;
}
    
std::vector<std::string> Sequence::splitChildren(std::string children) const{
    std::vector<std::string> childs;
    int depth = 0;
    int start = 0;
    for(int i=0;i<children.length();i++){
        if(children[i] == '['){
            depth++;
        }else if(children[i] == ']'){
            depth--;
            if(depth == 0){
                string s = children.substr(start,(i-start)+1);
                childs.push_back(s);
                start = i;
            }
        }else if(children[i] == ',' && depth == 0){
            start = i+1;
        }
    }
    return childs;
}
}
